package com.bizmda.bizsip.app.client;

import cn.hutool.core.text.StrFormatter;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.bizmda.bizsip.common.*;
import com.bizmda.bizsip.app.config.AppServiceMapping;
import com.bizmda.bizsip.app.config.RabbitmqConfig;
import com.bizmda.bizsip.app.executor.AbstractAppExecutor;
import com.bizmda.bizsip.service.AppLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class DelayAppServiceClientMethod {
    private final Method method;
    private final DelayAppServiceClientProxy delayServiceClientProxy;

    private RabbitTemplate rabbitTemplate;
    private AppServiceMapping appServiceMapping;
    private AppLogService appLogService;

    public DelayAppServiceClientMethod(Method method, DelayAppServiceClientProxy delayAppServiceClientProxy) {
        this.method = method;
        this.delayServiceClientProxy = delayAppServiceClientProxy;
        this.rabbitTemplate = SpringUtil.getBean(RabbitTemplate.class);
        this.appServiceMapping = SpringUtil.getBean(AppServiceMapping.class);
        this.appLogService = SpringUtil.getBean(AppLogService.class);
    }

    public Object execute(Object[] args) throws BizException{
        String serviceId = this.delayServiceClientProxy.getBizServiceId();
        int[] delayMilliseconds = this.delayServiceClientProxy.getDelayMilliseconds();
        JSONObject jsonObject = new JSONObject();
        if (this.delayServiceClientProxy.getMapperInterface().equals(BizMessageInterface.class)) {
            if (args[0] instanceof JSONObject) {
                jsonObject = (JSONObject) args[0];
            }
            else {
                jsonObject = JSONUtil.parseObj(args[0]);
            }
        }
        else {
            jsonObject.set("className", this.delayServiceClientProxy.getMapperInterface().getName());
            jsonObject.set("methodName", this.method.getName());
            jsonObject.set("params", JSONUtil.parseArray(args));
        }
        BizMessage<JSONObject> inMessage = BizTools.bizMessageThreadLocal.get();
        inMessage.setData(jsonObject);

        AbstractAppExecutor appExecutor = this.appServiceMapping.getAppExecutor(serviceId);
        if (appExecutor == null) {
            throw new BizException(BizResultEnum.APP_SERVICE_NOT_FOUND,
                            StrFormatter.format("聚合服务不存在:{}",serviceId));
        }
        BizMessage<JSONObject> childBizMessage = BizMessage.createChildTransaction(serviceId,inMessage);

        Map<String,Object> map = new HashMap<>(16);
        map.put("serviceId",serviceId);
        map.put("bizmessage",childBizMessage);
        map.put("retryCount",0);
        map.put("delayMilliseconds",delayMilliseconds);
        int delayMillisecond = delayMilliseconds.length>0 ? delayMilliseconds[0]:0;
        log.debug("调用延迟App服务: {},第1次，延迟时间[{}ms]",serviceId,delayMillisecond);
        log.trace("调用延迟App服务请求报文:\n{}",BizUtils.buildBizMessageLog(childBizMessage));
        rabbitTemplate.convertAndSend(RabbitmqConfig.DELAY_SERVICE_EXCHANGE, RabbitmqConfig.DELAY_SERVICE_ROUTING_KEY, map,
                new MessagePostProcessor() {
                    @Override
                    public Message postProcessMessage(Message message) {
                        //设置消息持久化
                        message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                        message.getMessageProperties().setDelay(delayMillisecond);
                        return message;
                    }
                });
        log.debug("发送交易挂起日志");
        this.appLogService.sendAppSuspendLog(inMessage,childBizMessage);
        if (this.delayServiceClientProxy.getMapperInterface().equals(BizMessageInterface.class)) {
            return childBizMessage;
        }
        else {
            return null;
        }
    }

}
